package com.xzq.erp.utils;

import jakarta.servlet.http.HttpServletResponse;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.http.MediaType;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * Excel工具类，用于生成Excel报表
 */
@Slf4j
public class ExcelUtils {

    /**
     * 导出Excel到输出流
     *
     * @param dataList     数据列表
     * @param columnConfig 列配置
     * @param outputStream 输出流
     * @param <T>          数据类型
     * @throws IOException IO异常
     */
    public static <T> void exportToOutputStream(List<T> dataList, List<ColumnConfig> columnConfig, OutputStream outputStream) throws IOException {
        try (Workbook workbook = createWorkbook(dataList, columnConfig)) {
            workbook.write(outputStream);
        }
    }

    /**
     * 导出Excel到文件
     *
     * @param dataList     数据列表
     * @param columnConfig 列配置
     * @param filePath     文件路径
     * @param <T>          数据类型
     * @throws IOException IO异常
     */
    public static <T> void exportToFile(List<T> dataList, List<ColumnConfig> columnConfig, String filePath) throws IOException {
        try (
                Workbook workbook = createWorkbook(dataList, columnConfig);
                FileOutputStream outputStream = new FileOutputStream(filePath)
        ) {
            workbook.write(outputStream);
        }
    }

    /**
     * 创建工作簿
     *
     * @param dataList     数据列表
     * @param columnConfig 列配置
     * @param <T>          数据类型
     * @return 工作簿
     */
    private static <T> Workbook createWorkbook(List<T> dataList, List<ColumnConfig> columnConfig) {
        Workbook workbook = new XSSFWorkbook();
        Sheet sheet = workbook.createSheet("Sheet1");

        // 创建表头样式
        CellStyle headerStyle = createHeaderStyle(workbook);
        // 创建数据样式
        CellStyle dataStyle = createDataStyle(workbook);

        // 创建表头 行
        Row headerRow = sheet.createRow(0);
        AtomicInteger colIndex = new AtomicInteger(0);
        columnConfig.forEach(config -> {
            // Cell 列
            Cell cell = headerRow.createCell(colIndex.getAndIncrement());
            cell.setCellValue(config.getTitle());
            cell.setCellStyle(headerStyle);
        });

        // 创建数据行
        if (dataList != null && !dataList.isEmpty()) {
            for (int i = 0; i < dataList.size(); i++) {
                Row dataRow = sheet.createRow(i + 1);
                T data = dataList.get(i);

                for (int j = 0; j < columnConfig.size(); j++) {
                    Cell cell = dataRow.createCell(j);
                    cell.setCellStyle(dataStyle);
                    setCellValue(cell, data, columnConfig.get(j));
                }
            }
        }

        // 自动调整列宽
        for (int i = 0; i < columnConfig.size(); i++) {
            sheet.autoSizeColumn(i);
            // 设置列宽至少15个字符宽度
            int width = sheet.getColumnWidth(i);
            if (width < 4000) {
                sheet.setColumnWidth(i, 4000);
            }
        }

        return workbook;
    }

    /**
     * 创建表头样式
     *
     * @param workbook 工作簿
     * @return 单元格样式
     */
    private static CellStyle createHeaderStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        Font font = workbook.createFont();
        font.setBold(true);
        style.setFont(font);
        style.setAlignment(HorizontalAlignment.CENTER);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        return style;
    }

    /**
     * 创建数据样式
     *
     * @param workbook 工作簿
     * @return 单元格样式
     */
    private static CellStyle createDataStyle(Workbook workbook) {
        CellStyle style = workbook.createCellStyle();
        style.setAlignment(HorizontalAlignment.LEFT);
        style.setVerticalAlignment(VerticalAlignment.CENTER);
        style.setBorderTop(BorderStyle.THIN);
        style.setBorderBottom(BorderStyle.THIN);
        style.setBorderLeft(BorderStyle.THIN);
        style.setBorderRight(BorderStyle.THIN);
        return style;
    }

    /**
     * 设置单元格值
     *
     * @param cell         单元格
     * @param data         数据对象
     * @param columnConfig 列配置
     * @param <T>          数据类型
     */
    private static <T> void setCellValue(Cell cell, T data, ColumnConfig columnConfig) {
        try {
            Object value = getFieldValue(data, columnConfig.getField());
            if (value == null) {
                cell.setCellValue("");
                return;
            }

            // 格式化器处理
            if (columnConfig.getFormatter() != null) {
                cell.setCellValue(columnConfig.getFormatter().apply(value));
                return;
            }

            // 根据数据类型设置单元格值
            if (value instanceof String) {
                cell.setCellValue((String) value);
            } else if (value instanceof Date) {
                if (columnConfig.getDateFormat() != null && !columnConfig.getDateFormat().isEmpty()) {
                    SimpleDateFormat dateFormat = new SimpleDateFormat(columnConfig.getDateFormat());
                    cell.setCellValue(dateFormat.format((Date) value));
                } else {
                    cell.setCellValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) value));
                }
            } else if (value instanceof Boolean) {
                cell.setCellValue((Boolean) value);
            } else if (value instanceof Number) {
                if (value instanceof Integer || value instanceof Long) {
                    cell.setCellValue(Double.parseDouble(value.toString()));
                } else if (value instanceof Double || value instanceof Float || value instanceof BigDecimal) {
                    if (columnConfig.getDecimalFormat() != null && !columnConfig.getDecimalFormat().isEmpty()) {
                        cell.setCellValue(String.format(columnConfig.getDecimalFormat(), value));
                    } else {
                        cell.setCellValue(Double.parseDouble(value.toString()));
                    }
                } else {
                    cell.setCellValue(value.toString());
                }
            } else {
                cell.setCellValue(value.toString());
            }
        } catch (Exception e) {
            log.error("设置单元格值异常", e);
            cell.setCellValue("");
        }
    }

    /**
     * 获取字段值
     *
     * @param obj       对象
     * @param fieldName 字段名
     * @return 字段值
     */
    private static Object getFieldValue(Object obj, String fieldName) {
        if (obj == null || fieldName == null || fieldName.isEmpty()) {
            return null;
        }

        try {
            // 处理嵌套属性，如 user.name
            if (fieldName.contains(".")) {
                String[] fieldNames = fieldName.split("\\.");
                Object nestedObj = obj;
                for (int i = 0; i < fieldNames.length; i++) {
                    if (nestedObj == null) {
                        return null;
                    }
                    
                    if (i == fieldNames.length - 1) {
                        return getFieldValueByName(fieldNames[i], nestedObj);
                    } else {
                        nestedObj = getFieldValueByName(fieldNames[i], nestedObj);
                    }
                }
                return null;
            } else {
                return getFieldValueByName(fieldName, obj);
            }
        } catch (Exception e) {
            log.error("获取字段值异常：" + fieldName, e);
            return null;
        }
    }

    /**
     * 根据字段名获取字段值
     *
     * @param fieldName 字段名
     * @param object    对象
     * @return 字段值
     */
    private static Object getFieldValueByName(String fieldName, Object object) {
        try {
            String firstLetter = fieldName.substring(0, 1).toUpperCase();
            String getter = "get" + firstLetter + fieldName.substring(1);
            Method method = object.getClass().getMethod(getter);
            return method.invoke(object);
        } catch (Exception e) {
            try {
                // 尝试直接访问字段
                Field field = getField(object.getClass(), fieldName);
                if (field != null) {
                    field.setAccessible(true);
                    return field.get(object);
                }
            } catch (Exception ex) {
                // 忽略异常
            }
            return null;
        }
    }

    /**
     * 获取字段，包括父类字段
     *
     * @param clazz     类
     * @param fieldName 字段名
     * @return 字段
     */
    private static Field getField(Class<?> clazz, String fieldName) {
        Field field = null;
        while (clazz != null && field == null) {
            try {
                field = clazz.getDeclaredField(fieldName);
            } catch (NoSuchFieldException e) {
                clazz = clazz.getSuperclass();
            }
        }
        return field;
    }

    /**
     * 构建列配置
     *
     * @param entityClass 实体类
     * @return 列配置列表
     */
    public static <T> List<ColumnConfig> buildColumnConfig(Class<T> entityClass) {
        Field[] fields = entityClass.getDeclaredFields();
        return Arrays.stream(fields)
                .map(field -> {
                    ColumnConfig config = new ColumnConfig();
                    config.setField(field.getName());
                    config.setTitle(field.getName()); // 默认使用字段名作为标题
                    return config;
                })
                .collect(Collectors.toList());
    }

    /**
     * 设置Excel响应头
     */
    public static void setExcelResponseHeader(HttpServletResponse response, String fileName) {
        try {
            fileName = URLEncoder.encode(fileName, "UTF-8");
            // 设置文件下载的头信息 以二进制流方式返回
            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
            response.setCharacterEncoding("utf-8");
            // 添加Content-Disposition头，指定为附件下载
            String format = "attachment;filename=%s.xlsx";
            response.setHeader("Content-Disposition", String.format(format, fileName));
            // 禁止缓存
            response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
            response.setHeader("Pragma", "no-cache");
            response.setHeader("Expires", "0");
        } catch (Exception e) {
            log.error("设置响应头异常", e);
        }
    }

    /**
     * 列配置
     */
    @Data
    public static class ColumnConfig {
        /**
         * 标题
         */
        private String title;
        
        /**
         * 字段名
         */
        private String field;
        
        /**
         * 日期格式
         */
        private String dateFormat;
        
        /**
         * 小数格式
         */
        private String decimalFormat;
        
        /**
         * 值格式化器
         */
        private ValueFormatter formatter;
        
        /**
         * 列宽
         */
        private Integer width;

        /**
         * 创建列配置
         *
         * @param title 标题
         * @param field 字段名
         * @return 列配置
         */
        public static ColumnConfig of(String title, String field) {
            ColumnConfig config = new ColumnConfig();
            config.setTitle(title);
            config.setField(field);
            return config;
        }

        /**
         * 设置日期格式
         *
         * @param dateFormat 日期格式
         * @return 列配置
         */
        public ColumnConfig withDateFormat(String dateFormat) {
            this.dateFormat = dateFormat;
            return this;
        }

        /**
         * 设置小数格式
         *
         * @param decimalFormat 小数格式
         * @return 列配置
         */
        public ColumnConfig withDecimalFormat(String decimalFormat) {
            this.decimalFormat = decimalFormat;
            return this;
        }

        /**
         * 设置值格式化器
         *
         * @param formatter 值格式化器
         * @return 列配置
         */
        public ColumnConfig withFormatter(ValueFormatter formatter) {
            this.formatter = formatter;
            return this;
        }

        /**
         * 设置列宽
         *
         * @param width 列宽
         * @return 列配置
         */
        public ColumnConfig withWidth(Integer width) {
            this.width = width;
            return this;
        }
    }

    /**
     * 值格式化器接口
     */
    @FunctionalInterface
    public interface ValueFormatter {
        /**
         * 格式化值
         *
         * @param value 原始值
         * @return 格式化后的值
         */
        String apply(Object value);
    }
} 